#!/usr/bin/python
# -*- coding: utf8 -*-
#
# clildr -- Python script to upload large amount of photos to Flickr.
# http://code.google.com/p/clildr/
# Copying and non-warranty: MIT License
#
# This code is based on http://sugree.com/node/84
# (c) 2007-2008 Sugree Phatanapherom
# http://creativecommons.org/licenses/by/3.0/

import os, sys
from optparse import OptionParser

try:
    from elementtree import ElementTree as ET
except Exception:
    import xml.etree.ElementTree as ET
    
try:
    import flickrapi
except Exception:
    sys.path.append(os.path.expanduser("~/bin/lib/python"))
    import flickrapi

class App:
    def __init__(self):
        self.options, self.args = self.parse_args()        
        self.read_rc()
        self.clildr_dir = '.clildr'
        self.clildr_lck = '.lck'
        self.files = []

    def files_add(self, name):
        lock = self.lock_name(name)
        if os.path.isfile(lock):
            print "LOCK EXIST", lock
            return
        base, ext = os.path.splitext(name)
        if '.jpg' == ext.lower():
            self.files.append(name)
        
    def handle_arg(self, arg):
        if os.path.isfile(arg):
            self.files_add(arg)
        else:
            for (path, dirs, files) in os.walk(arg):
                if os.path.basename(path) != self.clildr_dir:
                    for file in files:
                        self.files_add(os.path.join(path, file))
    
    def read_rc(self):
        self.api_key = None
        self.api_secret = None
        self.user_id = None
        try:
            fp = open(os.path.expanduser("~/.clildrrc"), 'r')            
            for line in fp.readlines():
                if not line.isspace():
                    (key, val) = line.split()
                    if 'api_key' == key:
                        self.api_key = val
                    elif 'api_secret' == key:
                        self.api_secret = val
                    elif 'user_id' == key:
                        self.user_id = val
            fp.close()
        except Exception, inst:
            print "rc read error", inst
        if not self.api_key or not self.api_secret or not self.user_id:
            print "missing rc data"
            raise SystemExit(2)
        
    def parse_args(self):
        parser = OptionParser()
        parser.add_option('--title', dest='title', default=None,
                          help='photo title')
        parser.add_option('--description', dest='description', default='',
                          help='photo description')
        parser.add_option('-t', '--tags', dest='tags', default='',
                          help='photo tags')
        parser.add_option('--public', dest='public', action='store_true',
                          help='is public?')
        parser.add_option('--family', dest='family', action='store_true',
                          help='is family?')
        parser.add_option('--friend', dest='friend', action='store_true',
                          help='is friend?')
        parser.add_option('--set', dest='photoset', default=None,
                          help='insert photos to a set, create if not exist')
        return parser.parse_args()
 
    def authenticate(self):
        self.flickr = flickrapi.FlickrAPI(self.api_key, self.api_secret, username = self.user_id)
        token, frob = self.flickr.get_token_part_one(perms='write')
        if not token:
            raw_input('Please ENTER after you authorized this program')
        self.flickr.get_token_part_two((token, frob))
 
    def progress(self, progress, done):
        if done:
            print '100%'
        else:
            print '%s%%' % progress            

    def lock_name(self, name):
        return os.path.join(os.path.dirname(name),
                            self.clildr_dir,
                            os.path.basename(name) + self.clildr_lck)

    def lock_create(self, lock, photoid):
        dir = os.path.dirname(lock)
        if not os.path.isdir(dir):
            os.mkdir(dir)
        fp = open(lock, 'w')
        fp.write("%d" % photoid + "\n")
        fp.close()
        print "LOCK NEW", lock
        
    def handle_file(self, name, setid = None):
        lock = self.lock_name(name)
        if os.path.isfile(lock):
            print "LOCK EXIST", lock
            return None
        photoid = self.upload_file(name)
        if photoid:
            self.lock_create(lock, photoid)
            if self.options.photoset:
                self.add_set(setid, photoid)
        return photoid

    def upload_file(self, name):
        params = {
            'filename': name,
            'title': self.options.title or os.path.basename(name),
            'description': self.options.description,
            'tags': self.options.tags,
            'is_public': int(self.options.public or True),
            'is_family': int(self.options.family or False),
            'is_friend': int(self.options.friend or False),
            'callback': self.progress,
        }
        print 'uploading %s' % name
        rsp = self.flickr.upload(**params)
        print ET.tostring(rsp)
        if 'ok' != rsp.attrib['stat']:
            return None
        photoid = self.rsp_photoid(rsp)
        return photoid

    def rsp_photoid(self, elem):
        for node in elem:
            print node.tag
            print node.text
            if 'photoid' == node.tag:
                return int(node.text)
        return None

    def get_setid(self, title):
        rsp = self.flickr.photosets_getList()
        ET.dump(rsp)
        print "******"
        for set in rsp.getiterator('photoset'):
            ET.dump(set)
            print "----"
            settitle = set.find('title')
            if title == settitle.text:
                return set.attrib['id']
        # create new set
        return None
    
    def add_set(self, id, photo):
        try:
            rsp = self.flickr.photosets_addPhoto(photoset_id = id, photo_id = photo)
            ET.dump(rsp)
            print "******"        
        except flickrapi.FlickrError, inst:
            print "add_set:", inst

    def run(self):
        for name in self.args:
            self.handle_arg(name)
        if 1 > len(self.files):
            print "NO FILES"
            return
        self.authenticate()
        setid = None
        if self.options.photoset:
            setid = self.get_setid(self.options.photoset)
            print "photoset: %s" % self.options.photoset
            print "setid : " + setid
        for name in self.files:
            print "FILE", name
            photoid = self.handle_file(name, setid)
 
if __name__ == '__main__':
    app = App()
    app.run()
    
